Skip to content

Add experimental wasm externref lang type - #159749

Closed
guybedford wants to merge 7 commits into
rust-lang:mainfrom
guybedford:wasm-externref
Closed

Add experimental wasm externref lang type#159749
guybedford wants to merge 7 commits into
rust-lang:mainfrom
guybedford:wasm-externref

Conversation

@guybedford

@guybedford guybedford commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

This adds an experimental core::arch::wasm32::externref type behind feature(wasm_externref) to support the same externref_t type that is possible for Clang on Wasm targets.

The use case is being able to receive and pass externref types between foreign functions, marshalling them between calls as opposed to storing them. This is currently a limitation for any Wasm projects which need to bind to foreign functions that marshall externrefs, requiring a lot of internal custom boilerplate wrapping to handle a type that is really a core part of the JS FFI boundary.

The approach taken is to implement a new ExternRef lang item as a scalar pointer in AddressSpace(10), LLVM's Wasm externref address space, with no further codegen changes necessary. externref is Copy (duplicating a reference is local.get), !Send/!Sync, and improper_ctypes treats it as FFI-safe.

externref usage is heavily restricted here to being treated as only a bare-position-only type. wf-check enforcement is added so that it is legal only as the top-level type of function parameters, return values and locals (function pointer signature slots included), and nowhere else - no references, aggregates, statics or generic arguments. All enforcement is at type-check time, and could be relaxed to become more flexible in future. For example, to support addressibility via llvm/llvm-project#201466 if that were to land.

Example usage:

#![feature(wasm_externref)]
use core::arch::wasm32::externref;

unsafe extern "C" {
    fn create_ref() -> externref;
    fn use_ref(v: externref);
}

// JS calls describe(obj) directly, identity-preserving
#[unsafe(no_mangle)]
pub extern "C" fn describe(v: externref) -> externref { v }

compiles to:

(func $describe (param externref) (result externref)
  local.get 0)

Test coverage includes a codegen test for addrspace(10) signatures, assembly test for .functype describe (externref) -> (externref), and a ui test for the position rules (12 error cases plus the allowed forms). Verified end-to-end in a JS host with identity preservation in both directions at -Copt-level=0 and 2.

Credit: Since the initial prototype of this work was done by @hoodmane I've added him as a co-author.

Made with AI assistance under my review.

Adds core::arch::wasm32::externref behind feature(wasm_externref): an
opaque host reference lowering to LLVM ptr addrspace(10), giving real
wasm reference types in extern "C" signatures.

externref is a bare-position-only type, following clang's
__externref_t semantics: legal only as the top-level type of function
parameters, return values and locals (function pointer signature slots
included), enforced at type-check time via wf checks and typeck
writeback. A monomorphization-time check backstops the remaining
codegen-only channels (e.g. coroutine captures).

Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com>
@rustbot

rustbot commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

stdarch is developed in its own repository. If possible, consider making this change to rust-lang/stdarch instead.

cc @Amanieu, @folkertdev, @sayantn

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jul 22, 2026
@rustbot

rustbot commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

r? @folkertdev

rustbot has assigned @folkertdev.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 74 candidates
  • Random selection from 21 candidates

@rust-log-analyzer

This comment has been minimized.

guybedford and others added 2 commits July 22, 2026 15:44
Define the type in core's own arch module (shadowing the core_arch glob
re-export) since the lang item is tightly coupled to compiler support
and stdarch syncs to a separate repository. Also adds a Debug impl,
required by core lints.

Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com>
Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com>
guybedford and others added 2 commits July 22, 2026 17:04
At opt-level 0 every local gets an alloca, which the wasm backend must
promote to wasm locals since reference types cannot enter linear
memory. Verifies eight simultaneously-live externrefs lower to
.local externref slots with no memory traffic.

Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com>
With -Cdebuginfo=2, user-visible SSA locals are spilled to allocas so
dbg.declare can reference them. wasm reference types cannot be stored
to linear memory, so the debug spill of an externref local hit a fatal
'Cannot select' in the wasm backend (any cargo dev-profile build using
externref locals). Skip the debuginfo spill for externref operands,
alongside the existing SVE predicate skip; like clang's __externref_t,
such variables get no memory-based debug location.

Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com>
@rust-log-analyzer

This comment has been minimized.

guybedford and others added 2 commits July 22, 2026 20:51
The gcc codegen backend cannot target wasm32, so even the minicore
auxiliary build panics at backend init in the gcc CI job.

Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com>
Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com>
@hoodmane

Copy link
Copy Markdown
Contributor

as a scalar pointer in AddressSpace(10)

Not anymore:
llvm/llvm-project#203165
Maybe we should wait until we bring in that change?

@guybedford

guybedford commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@hoodmane I think that layers with this work well - it can loosen the compile-time checks as mentioned in the description, while still enabling the primary use case now.

@hoodmane

Copy link
Copy Markdown
Contributor

it can loosen the compile-time checks

It can? It seems orthogonal to that to me. The representation of an externref changed from a pointer to a funny address space to a target ext type. Ideally we wait until that change makes it to rust/llvm to avoid churn I think. But maybe there's something I'm misunderstanding.

@guybedford

Copy link
Copy Markdown
Contributor Author

@hoodmane the representation affects the compiled output, not the Rust code usage, and it is under an experimental feature. Not sure what the concern is?

@hoodmane

Copy link
Copy Markdown
Contributor

Well sure maybe it's fine. If we're lucky the people who roll llvm might fix it for us.

@guybedford

Copy link
Copy Markdown
Contributor Author

Yeah appreciated for the heads up on that, I'd be happy to help rebase to LLVM 23 when the time comes. It should be a fairly simple codegen diff, not a fundamental design change.

@folkertdev

Copy link
Copy Markdown
Contributor

The upgrade to LLVM 23 is already in the queue (i.e. will merge in the coming days), so that should be the foundation for any new features. When you can no longer just use on the core pointer type, but need something custom to get your type into the backend, I suspect the implementation gets more complicated.

Beyond that: extensions like this need at least good vibes from target maintainers. Was this change discussed with anyone in the rust project at all? At first glance this looks like an RFC (or similar) might be appropriate.

@ChayimFriedman2

Copy link
Copy Markdown
Contributor

This is a fundamentally new kind of type - this seems to need more than just a PR, maybe a lang experiment or even a RFC.

@folkertdev

Copy link
Copy Markdown
Contributor

Yeah, let's discuss this in #t-lang > wasm `externref`.

@guybedford

Copy link
Copy Markdown
Contributor Author

The upgrade to LLVM 23 is already in the queue

Oh wow, that is some great timing. I will rework the PR to that then, per the discussion.

Per discussion, let me close this for now, to return to it with process ducks lined up rather.

@guybedford guybedford closed this Jul 23, 2026
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jul 23, 2026
@guybedford
guybedford deleted the wasm-externref branch July 24, 2026 05:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants